/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - graphics/buffers
// Copyright( c) 2015.  All Rights Reserved
//
// File:		AEGpuResource.h
// Author:		Gianluca Belardelli
// Date:		19/12/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AEGPURESOURCE_H_
#define _AEGPURESOURCE_H_

/// \brief La classe AEGpuResource si occupa di gestire una risorsa GPU che pu&ograve; essere
/// un vertex buffer o un index buffer. Tramite i metodi della classe &egrave; possibile
/// lockare e copiare i dati nella memoria della GPU.
class AEGpuResource : public AEResource
{
// Members
protected:
	void		*m_lpSystemCopy;	/// \internal Puntatore alla copia in memoria di sistema.
	void		*m_lpLockedPtr;		/// \internal Puntatore alla memoria attualmente lockata.

	AEUINT32	m_uiSize;			/// \internal Dimensione in byte della risorsa.
	AEUINT32	m_uiUsageFlags;		/// \internal Flag di utilizzo impostati.
	AEUINT32	m_uiBindFlags;		/// \internal Flag di binding impostati.
	AEUINT32	m_uiLockFlags;		/// \internal Flag di lock impostati.
	AEUINT32	m_uiLockedOffset;	/// \internal Offset di lock.
	AEUINT32	m_uiLockedSize;		/// \internal Dimensione dell'area lockata.

	AEBOOL32	m_bHasSysmemCopy;	/// \internal Specifica se esiste la copia in memoria di sistema.
	AEBOOL32	m_bSafeCleanUp;		/// \internal Specifica se il distruttore dealloca tutto.

#if defined( AE_OPENGL ) || ( AE_OPENGLES2 )
	AEUINT32	m_uiHandle;			/// \internal Handle specifico OpenGL della risorsa.
	GLenum		m_eOGLUsage;		/// \internal Flag di utilizzo specifico OpenGL della risorsa.
	GLenum		m_eBindTarget;		/// \internal Flag di binding specifico OpenGL della risorsa.
#endif

// Methods
protected:
	/// \internal Inizializzazione specifica per piattaforma.
	void _initResourcePlatformSpecific( void );

	/// \internal Inizializzazione specifica per piattaforma.
	void _deinitResourcePlatformSpecific( void );

public:
	/// \brief Costruttore della classe AEGpuResource.
	/// \param lpParentManager Resource manager al quale apparterr&agrave; questa risorsa.
	/// \param uiSize Dimensione in bytes della risorsa.
	/// \param uiUsageFlags Pu&ograve; assumere i valori di \b AEMEMUSAGE_STATIC, \b AEMEMUSAGE_DYNAMIC,
	/// \b AEMEMUSAGE_STREAM e \b AEMEMUSAGE_STATIC_UNMANAGED.<br>
	/// In generale si dovrebbe utilizzare \b AEMEMUSAGE_STATIC per dati che sono specificati una sola
	/// volta e non cambiano mai. \b AEMEMUSAGE_STREAM dovrebbe essere utilizzato per quei dati che vengono
	/// modificati spesso a run-time ma che hanno una frequenza di rendering superiore alla frequenza
	/// di aggiornamento. \b AEMEMUSAGE_DYNAMIC &egrave; la soluzione migliore per quei dati che hanno una
	/// frequenza di rendering e aggiornamento molto simile o uguale.<br>
	/// \b AEMEMUSAGE_STATIC_UNMANAGED &egrave; simile a \b AEMEMUSAGE_STATIC ma consuma meno memoria perch&egrave;
	/// il buffer in memoria di sistema non viene mantenuto automaticamente, ci&ograve; significa
	/// che sar&agrave; necessario gestire manualmente gli eventi di lost device.
	/// \param uiBindFlags Specifica i flags utilizzati per il binding della risorsa sulla GPU.
	/// I valori possibili sono:
	///   \li \b AEBIND_INDEX_BUFFER: Permette a questa risorsa di essere utilizzata come un index buffer.
	///   \li \b AEBIND_VERTEX_BUFFER: Permette a questa risorsa di essere utilizzata come un vertex buffer.
	/// \param bHasSysmemCopy Flag che specifica se la risorsa ha una copia dei dati in memoria di sistema.<br>
	/// Il flag dovrebbe essere impostato se si desidera effettuare operazioni di lettura sul buffer.
	/// \param bSafeCleanUp Flag che permette di distruggere la risorsa garantendo che la GPU non la sta
	/// pi&ugrave; utilizzando.
	/// \param lpInternalName Stringa contenente il nome della risorsa.
	/// \note A seconda della piattaforma utilizzata la configurazione di \a uiUsageFlags, \a uiBindFlags e/o
	/// l'utilizzo di una copia in memoria di sistema, pu&ograve; avere implicazioni sull'accessibilit&agrave; a questa
	/// risorsa. Ad esempio, il fatto di non utilizzare una copia in memoria di sistema significa che su
	/// una piattaforma OpenGL ES2.0 i dati della risorsa non potranno essere letti, oppure utilizzando
	/// una risorsa con \b AEMEMUSAGE_STATIC su una piattaforma DX11 significa che non pu&ograve; essere lockata.
	AE_DLLIMPEXP AEGpuResource( AEResourceManager *lpParentManager, 
								AEUINT32 uiSize,
								AEUINT32 uiUsageFlags, 
								AEUINT32 uiBindFlags,
								AEBOOL32 bHasSysmemCopy, 
								AEBOOL32 bSafeCleanUp = AETRUE,
								const char *lpInternalName = "GpuResource");

	/// \brief Distruttore
	AE_DLLIMPEXP virtual ~AEGpuResource( void );

	/// \brief
	///   Ensures that the hardware resource exists. Recreates its data from internal system memory copy if necessary 
	///   and (re-)initializes resource views created from this resource (if applicable).
	AE_DLLIMPEXP virtual AEBOOL32 Reload( void );

	/// \brief
	///   Unloads the hardware resource and de-initializes resource views created from this resource.
	AE_DLLIMPEXP virtual AEBOOL32 Unload( void );

	/// \brief Riempie il buffer di memoria della risorsa con i dati passati sul parametro \c lpSourceData.
	/// \param lpSourceData Puntatore ai dati da copiare nella risorsa.
	/// \param uiOffset Offset all'interno del buffer della risorsa dal quale iniziare a copiare i dati.
	/// \param uiSize Dimensione in bytes dei dati da copiare.
	/// \param uiLockFlags Flag di locking. Su alcune piattaforme la combinazione dei seguenti flags permette
	/// un'ottimizzazione delle performance.
	///   \li \b AELOCKFLAG_DISCARDABLE: Specificare questo flag se \b tutti i dati presenti nell'area
	///        di memoria devono essere sovrascritti. Questo permette di rimpiazzare tutti i dati interni
	///        con una nuova area di memoria. In questo modo si evita di attendere che la GPU finisca di
	///        utilizzare questa risorsa.<br> La memoria correntemente utilizzata dalla GPU sar&agrave; rilasciata
	///        non appena avr&agrave; finito di utilizzarla e rimpiazzata con quella appena creata.
	///   \li \b AELOCKFLAG_NOOVERWRITE: Specificare questo flag se &egrave; garantito che l'area di memoria
	///        lockata non &egrave attualmente in uso dalla GPU.<br> Questo permette un'accesso diretto alla
	///        memoria evitando cos&igrave; le attese di utilizzo da parte della GPU.
	AE_DLLIMPEXP virtual void FillWithData( const void *lpSourceData, AEUINT32 uiOffset, AEUINT32 uiSize, AEUINT32 uiLockFlags = AELOCKFLAG_NOOVERWRITE );

	/// \brief Esegue un lock sulla risorsa GPU per accedere in lettura e/o scrittura.<br>
	/// Il metodo fornisce un accesso sicuro alla memoria interna della risorsa GPU. Specificando i flag di lock
	/// le performance possono essere migliorate considerevolmente evitando inutili trasferimenti di dati.<br>
	/// Se la risorsa ha una copia nella memoria di sistema, questo metodo ritorna un puntatore a quest'area.
	/// L'upload dei dati sar&agrave; effettuato nel momento in cui la risorsa viene slockata ( a meno che
	/// non &egrave; stato utilizzato il flag \b AELOCKFLAG_READONLY ).
	/// \note Il lock parziale della risorsa &egrave; possibile impostando opportunamente i valori dei parametri
	/// \c uiOffset e \c uiSize, ma non &egrave; consigliato in quanto non supportato da tutte le piattaforme.
	/// \param uiLockFlags Flag che specificano il tipo di lock desiderato.
	/// I valori possibili sono:
	///   \li \b AELOCKFLAG_DISCARDABLE: Specificare questo flag se \b tutti i dati presenti nell'area
	///        di memoria devono essere sovrascritti. Questo permette di rimpiazzare tutti i dati interni
	///        con una nuova area di memoria. In questo modo si evita di attendere che la GPU finisca di
	///        utilizzare questa risorsa. La memoria correntemente utilizzata dalla GPU sar&agrave; rilasciata
	///        non appena avr&agrave; finito di utilizzarla e rimpiazzata con quella appena creata.
	///   \li \b AELOCKFLAG_READONLY: Specificare questo flag se non c'&egrave; la necessit&agrave; di
	///        scrivere i dati in memoria. Questo permette di non eseguire l'upload dei dati sulla GPU.
	///   \li \b AELOCKFLAG_NOOVERWRITE: Specificare questo flag se &egrave; garantito che l'area di memoria
	///        lockata non &egrave attualmente in uso dalla GPU. Questo permette un'accesso diretto alla
	///        memoria evitando cos&igrave; le attese di utilizzo da parte della GPU.
	///   \li \b AELOCKFLAG_REPLACE_ALL: Specificare questo flag se \b tutta la memoria lockata deve essere
	///        sovrascritta.
	/// \internal <center><TABLE style="border: 1px solid black;border-spacing: 5px;background-color: #f1f1c1;">
	/// <TR><TD rowspan="2"><IMG SRC="..\img\opengl.jpg" WIDTH="80" ALIGN="LEFT"></TD>
	/// <TD>
	/// Sulla piattaforma OpenGL i flags di lock sono mappati nel seguente modo:
	///	\li \b AELOCKFLAG_DISCARDABLE = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT
	///	\li \b AELOCKFLAG_READONLY = GL_MAP_READ_BIT
	///	\li \b AELOCKFLAG_NOOVERWRITE = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT
	///	\li \b AELOCKFLAG_REPLACE_ALL = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT
	/// </TD></TR></TABLE></center>
	/// \param uiOffset Offset dal quale la memoria lockata deve iniziare.
	/// \param uiSize Quanti byte di memoria &egrave; necessario lockare ( Specificare 0
	/// per l'intero buffer ).
	/// \returns Un puntatore ai dati lockati.
	/// \sa AEGpuResource::Unlock
	AE_DLLIMPEXP virtual void *Lock( AEUINT32 uiLockFlags, AEUINT32 uiOffset = 0, AEUINT32 uiSize = 0 );

	/// \brief Esegue l'unlock della risorsa GPU.<br>
	/// Se la risorsa ha una copia nella memoria di sistema, questo metodo esegue l'upload dei dati 
	/// dalla memoria di sistema alla memoria video ( a meno che non &egrave; stato utilizzato 
	/// il flag \b AELOCKFLAG_READONLY ).
	/// \sa AEGpuResource::Lock
	AE_DLLIMPEXP virtual void Unlock( void );

	/// \brief Ritorna \b AETRUE se la risorsa &egrave; lockata, altrimenti \b AEFALSE.
	AE_FORCEINLINE AEBOOL32 IsLocked( void ) const;

	/// \brief Ritorna un puntatore di tipo void* alla memoria lockata.
	AE_FORCEINLINE void *GetLockedPtr( void ) const;

	/// \brief Ritorna \b AETRUE se questa risorsa pu&ograve; essere lockata in lettura,
	/// altrimenti \b AEFALSE.
	AE_DLLIMPEXP AEBOOL32 CanBeLockedForReading( void ) const;
	
	/// \brief Ritorna \b AETRUE se la risorsa ha una copia dei suoi dati nella
	/// memoria di sistema, altrimenti \b AEFALSE.
	AE_FORCEINLINE AEBOOL32 HasSysmemCopy( void ) const;

	/// \brief Ritorna un puntatore di tipo void* alla copia della risorsa
	/// presente in memoria di sistema.<br> Se la risorsa non ha una copia in
	/// memoria di sistema il valore di ritorno sar&agrave AENULL.
	AE_FORCEINLINE void *GetSysmemBufferPtr( void );

	/// \brief Ritorna la dimensione interna in bytes di questa risorsa.
	AE_FORCEINLINE AEUINT32 GetSize( void ) const;

	/// \brief Ritorna la combinazione dei flag di utilizzo impostati per questa risorsa.
	/// \sa AEGpuResource::AEGpuResource per quanto riguarda i flag.
	AE_FORCEINLINE AEUINT32 GetUsageFlags( void ) const;

	/// \brief Ritorna il tipo di binding impostato per questa risorsa.
	/// \sa AEGpuResource::AEGpuResource per quanto riguarda il tipo di binding.
	AE_FORCEINLINE AEUINT32 GetBindFlags( void ) const;

	/// \brief
	///   Overridden function to evaluate memory consumption.
	//AE_DLLIMPEXP virtual void AccumulateMemoryFootprint( size_t &iUniqueSys, size_t &iUniqueGPU, size_t &iDependentSys, size_t &iDependentGPU );

#if defined( AE_OPENGL ) || defined ( AE_OPENGLES2 ) || defined( AE_OPENGLES3 )
	AE_FORCEINLINE AEUINT32 GetHandle( void ) const;
#endif

};

#include "AEGpuResource.inl"

#endif // _AEGPURESOURCE_H_
